package com.bolt.support.spring.jpa.repository;

import com.bolt.convention.data.DefaultPageInfo;
import com.bolt.convention.data.PageInfo;
import com.bolt.convention.data.Pagination;
import com.bolt.support.spring.jpa.filter.GroupPropertyFilter;
import com.bolt.support.spring.jpa.specification.PropertyFilterSpecification;
import com.bolt.support.spring.jpa.specification.Specifications;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.support.JpaEntityInformation;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;

import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import java.io.Serializable;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

/**
 * Created by Administrator on 2017/8/9.
 */
public class ExtBasicJpaRepositoryImpl<T, ID extends Serializable>
        extends SimpleJpaRepository <T, ID> implements BasicJpaRepository <T, ID> {


    private EntityManager entityManager;

    public ExtBasicJpaRepositoryImpl(JpaEntityInformation entityInformation, EntityManager entityManager) {
        super(entityInformation, entityManager);
        this.entityManager = entityManager;
    }


    public List <T> findAll(GroupPropertyFilter filters) {
        if (Objects.isNull(filters.getSort())) {
            return findAll(Specifications.get(filters), Sort.unsorted());
        } else {
            return findAll(Specifications.get(filters), filters.getSort());
        }
    }

    @Override
    @Deprecated
    public Page <T> findPage(Pageable pageable, GroupPropertyFilter filters) {
        return findAll(Specifications.get(filters), pageable);
    }


    @Override
    public PageInfo <T> findPage(Pagination pagination, GroupPropertyFilter filters) {
        Sort sort = Objects.isNull(pagination.getSort()) ? Sort.unsorted() : pagination.getSort();
        Specification spec = Specifications.get(filters);
        TypedQuery <T> query = getQuery(spec, sort);

        query.setFirstResult(pagination.getOffset());
        query.setMaxResults(pagination.getPageSize());

        TypedQuery <Long> countQuery = getCountQuery(spec, getDomainClass());
        List <Long> totals = countQuery.getResultList();
        Long total = 0L;
        for (Long element : totals) {
            total += element == null ? 0 : element;
        }
        return new DefaultPageInfo <T>(pagination, query.getResultList(), total);
    }


    public List <T> findLimit(Specification spec, Sort sort, int limit) {
        TypedQuery <T> query = getQuery(spec, Objects.isNull(sort) ? Sort.unsorted() : sort);
        query.setFirstResult(0);
        query.setMaxResults(limit);
        return query.getResultList();
    }

    @Override
    public Optional <T> findOne(GroupPropertyFilter filters) {
        Specification <T> specification = new PropertyFilterSpecification <>(filters);
        return findOne(specification);
    }


    @Override
    public ID getIdentifier(T entity) {
        return (ID) this.entityManager.getEntityManagerFactory().getPersistenceUnitUtil().getIdentifier(entity);

    }

    @Override
    public boolean isManaged(T entity) {
        return this.entityManager.contains(entity);
    }


}
